/*
 * C4.11.1.c
 *
 *  Created on: 2012/11/15
 *      Author: shenming
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "rule_info.h"
#include "core.h"
#include "trace.h"
#include "TraceAst.h"
#include "rule_lib.h"

static const PSZ RuleID = "C4.11.1";

static const PSZ MESSAGE_ENG =
		"Using assignment operator '%s %s' in expression with boolean type";
static const PSZ MESSAGE_JPN = "ブール型の式中代入演算子'%s %s'使用";
static const PSZ MESSAGE_CHS = "在布尔型的式中使用了代入演算子'%s %s'";

static const U2 RANK = MSG_RANK_ERR;

static PRULEOUT pRuleHead;
static PRULEOUT pRuleTail;

/******************************************************************
 * static function:
 * checkAssignment
 //TODO
 * checking first level(not paren) now
 * check all sub?
 *******************************************************************/
static INT checkAssignment(AST exp, PSZ * opKind) {
	U4 kind = 0;
	if (exp <= 0) {
		return RULE_RESULT_OK;
	}
	exp = getFstUnpChdExp(exp);
	kind = CExpression.getOpKind(exp);
	if (!CExpressionOpKind.isAssignmentOp(kind)) {
		return RULE_RESULT_OK;
	} else {
		if (CAssignOpKind.isAssignment(kind)) {
			*opKind = "=";
		} else if (CAssignOpKind.isMultiAssignOp(kind)) {
			*opKind = "*=";
		} else if (CAssignOpKind.isDivisionAssignOp(kind)) {
			*opKind = "/=";
		} else if (CAssignOpKind.isRemainderAssignOp(kind)) {
			*opKind = "%=";
		} else if (CAssignOpKind.isAddAssignOp(kind)) {
			*opKind = "+=";
		} else if (CAssignOpKind.isSubtractionAssignOp(kind)) {
			*opKind = "-=";
		} else if (CAssignOpKind.isLeftShiftAssignOp(kind)) {
			*opKind = "<<=";
		} else if (CAssignOpKind.isRightShiftAssignOp(kind)) {
			*opKind = ">>=";
		} else if (CAssignOpKind.isBitAndAssignOp(kind)) {
			*opKind = "&amp;=";
		} else if (CAssignOpKind.isBitExOrAssignOp(kind)) {
			*opKind = "^=";
		} else if (CAssignOpKind.isBitOrAssignOp(kind)) {
			*opKind = "|=";
		}
	}
	return RULE_RESULT_NG;
}

/******************************************************************
 * main logic
 *******************************************************************/
static S4 RuleMain(U2 kind, AST index, U4 event) {
	INT result = RULE_RESULT_OK;
	INT result2 = RULE_RESULT_OK;
	PRULEOUT newNode = NULL;
	PRULEOUT tmpNode = NULL;
	PRULEOUT tmpNode1 = NULL;

	AST codeScp = 0;
	U4 expKind = 0;
	AST exp = 0;
	AST exp2 = 0;
	PSZ opKind = "";
	PSZ opKind2 = "";

	if ((kind != TR_KIND_STATEMENT) && (kind != TR_KIND_EXPRESSION)) {
		return EXIT_SUCCESS;
	}

	if (!(event & EVT_STATEMENT) && !(event & EVT_EXPRESSION)) {
		return EXIT_SUCCESS;
	}

	if (kind == TR_KIND_STATEMENT) {
		if (CStatement.isIf(index)) {
			exp = CStatement.if_getCondExp(index);
		} else if (CStatement.isWhile(index)) {
			exp = CStatement.while_getCondExp(index);
		} else if (CStatement.isDo(index)) {
			exp = CStatement.do_getCondExp(index);
		} else if (CStatement.isFor(index)) {
			exp = CStatement.for_getCondExp(index);
		} else {
			return EXIT_SUCCESS;
		}
	} else if (kind == TR_KIND_EXPRESSION) {
		expKind = CExpression.getOpKind(index);
		if (CExpressionOpKind.isEqualityOp(expKind)
				|| CExpressionOpKind.isRelationalOp(expKind)
				|| CExpressionOpKind.isLogicalAndOp(expKind)
				|| CExpressionOpKind.isLogicalOrOp(expKind)) {
			exp = CExpression.getLeftNode(index);
			exp2 = CExpression.getRightNode(index);
		} else if (CUnaryOpKind.isValueNegation(expKind)
				|| CConditionOpKind.isQuestionOp(expKind)) {
			exp = CExpression.getLeftNode(index);
		} else {
			return EXIT_SUCCESS;
		}
	}

	result = checkAssignment(exp, &opKind);
	if (exp2 > 0) {
		result2 = checkAssignment(exp2, &opKind2);
		if (result2 == RULE_RESULT_NG) {
			result = RULE_RESULT_NG;
		}
	}

	if (result == RULE_RESULT_OK) {
		return EXIT_SUCCESS;
	}

	/*re-checked?*/
	tmpNode = pRuleHead;
	while (tmpNode != NULL ) {
		if (tmpNode->indexInfo == exp) {
			if (result > RULE_RESULT_OK) {
				result = RULE_RESULT_OK;
			} else {
				if (tmpNode == pRuleHead) {
					pRuleHead = pRuleHead->next;
					free(tmpNode);
				} else if (tmpNode == pRuleTail) {
					tmpNode1->next = NULL;
					pRuleTail = tmpNode1;
					free(tmpNode);
				} else {
					tmpNode1->next = tmpNode->next;
					free(tmpNode);
				}
			}
			break;
		}
		tmpNode1 = tmpNode;
		tmpNode = tmpNode->next;
	}

	/*make result struct*/
	if (result > RULE_RESULT_OK) {
		newNode = (PRULEOUT) malloc(sizeof(RULEOUT));
		if (pRuleHead == NULL ) {
			pRuleHead = newNode;
		}

		codeScp = CExpression.getCodeScope(exp);
		newNode->indexInfo = exp;
		newNode->fileIndex = CCodeScope.getFileIndex(codeScp);
		newNode->beginLine = CCodeScope.getBeginLine(codeScp);
		newNode->beginCol = CCodeScope.getBeginLineOffset(codeScp);
		newNode->endLine = CCodeScope.getEndLine(codeScp);
		newNode->endCol = CCodeScope.getEndLineOffset(codeScp);
		newNode->ruleID = RuleID;
		newNode->errRank = RANK;

		sprintf(newNode->msgBuf_eng, MESSAGE_ENG, opKind, opKind2);
		sprintf(newNode->msgBuf_chs, MESSAGE_CHS, opKind, opKind2);
		sprintf(newNode->msgBuf_jpn, MESSAGE_JPN, opKind, opKind2);

		newNode->rfileIndex = 0;
		newNode->rlocLine = 0;
		newNode->next = NULL;

		if (pRuleTail != NULL ) {
			pRuleTail->next = newNode;
		}

		pRuleTail = newNode;
	}

	return EXIT_SUCCESS;
}

VOID C4_11_1_register(VOID) {
	PRULEMAN * pCurRule = &stRuleManager;
	PRULEMAN newRuleMan = (PRULEMAN) malloc(sizeof(RULEMAN));
	memset(newRuleMan, 0, sizeof(RULEMAN));
	newRuleMan->ruleID = RuleID;
	newRuleMan->ruleSwitch = OFF;
	newRuleMan->headOut = &pRuleHead;
	newRuleMan->tailOut = &pRuleTail;
	newRuleMan->ruleMain_cmd = NULL;
	newRuleMan->ruleMain_ast = RuleMain;
	newRuleMan->nextRule = NULL;
	if (stRuleManager == NULL ) {
		stRuleManager = newRuleMan;
	} else {
		while ((*pCurRule)->nextRule != NULL ) {
			pCurRule = &((*pCurRule)->nextRule);
		}
		(*pCurRule)->nextRule = newRuleMan;
	}
}

